简单工厂
代码示例
|
|
建造者模式
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
适用场景
主要用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化
建造者模式的好处是的建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了
结构图

代码实例
|
|
单例模式
定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点
代码实例
首先写一个简单的单例类
以上简单的单例类在多线程并发的时候就会出问题,针对多线程并发访问的环境下对getInstance()方法进行加锁
以上代码解决了并发访问的问题,但是性能有所下降,因为每次访问getInstance()都会加锁,而实际上只需要当instance为空的时候才需要加锁,所以进行以下优化
上线代码貌似既解决了并发又解决了性能,但实际上仍然是由问题的,因为在java中创建对象和赋值是分开进行的,即instance = new Singleton();是分两步执行的,并且JVM并不能保证这两步操作的先后顺序。
也就说有可能jvm先为新的Singleton实例分配一段内存空间赋值给instance,然后再再创建Singleton实例,这样就可能出错了,我们以A、B两个线程为例:
- A、B线程同时进入了第一个if判断。
- A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();
- 由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。
- B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。
- 此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。
对改程序做进一步优化:
另外还有一种解决办法就是利用静态内部类来实现,jvm机制可以保证当一个类被加载时,这个类的加载过程是线程互斥的,这样就可以利用这个特性,这样当我们第一次调用getInstance()时,JVM可以保证我们在调用过程中的instance只会被创建一次,代码如下:
工厂方法
定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到子类
适用场景
工厂方法适用于以下几种场景
- 当一个类不知道它所必须创建的对象类的时候
- 当一个类希望由它的子类来指定它所创建的对象的时候
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候
结构图

代码示例
|
|
抽象工厂模式
定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类
抽象工厂与工厂方法的区别
工厂方法模式:
- 一个抽象产品类,可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
- 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品。
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
工厂方法只需创建一种产品,他的着重点在于”怎么创建”产品上,也就是说如果你的大量代码很可能围绕着这种产品的构造,初始化这些细节上面。也因为如此,类似的产品之间有很多可以复用的特征,所以会和模版方法相随。
抽象工厂需要创建一些列产品,着重点在于”创建哪些”产品上,也就是说如果你的主要任务是划分不同差异的产品线,并且尽量保持每条产品线接口一致,从而可以从同一个抽象工厂继承。
例子:
一个抽象服装店类可以出售裤子和衣服两个产品。
一个抽象裤子工厂有且只有一条生产线专门生产裤子;
一个裤子抽象产品类有耐克和阿迪达斯两个具体产品类,
一个抽象衣服工厂有且只有一套生产线专门生产衣服
衣服抽象产品类有柒牌和劲霸男装有个具体产品类,
具体服装店A出售柒牌衣服+耐克裤子
具体服装店B出售劲霸衣服+阿迪达斯裤子
这里的服务装店对应的就是抽象工厂,衣服和裤子工厂及其生产线对应的是工厂方法
原型模式
定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象[设计模式]
浅复制与深复制
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。
简单来说,深复制进行了完全彻底的复制,而浅复制不彻底。
适用场景
使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。
因为以上优点,所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。